#include "widgets.h"

#include "draw.h"
#include "log.h"
#include <stdio.h>

////////////////////////////////////////////////////////////////////////////////

Button::Button(const char* text):
  _text(text)
{
  setDim(80, 30);
  
  _down = false;
}

bool Button::handleMousePress(const MousePressEvent& event)
{
  _down = true;
  
  return true;
}

bool Button::handleMouseRelease(const MousePressEvent& event)
{
  if (_down)
  {
    _down = false;
    
    postEvent(BUTTON_PRESSED);
  }
  
  return true;
}

void Button::draw()
{
  Rect rect(_pos.x, _pos.y, _dim.w, _dim.h);
  Rect font_rect(rect.x, rect.y, rect.w - 2, rect.h - 2);
  
  if (_down)
  {
    font_rect.x += 2;
    font_rect.y += 2;
    
    Draw_drawRect3D(rect, 2, Colour::D_GREY, Colour::GREY, Colour::L_GREY);
    GUI_print(font_rect, TEXT_HORZ_ALIGN_CENTER, TEXT_VERT_ALIGN_CENTER,
      Colour::BLACK, _text.str());
  }
  else
  {
    Draw_drawRect3D(rect, 2, Colour::L_GREY, Colour::GREY, Colour::D_GREY);
    GUI_print(font_rect, TEXT_HORZ_ALIGN_CENTER, TEXT_VERT_ALIGN_CENTER,
      Colour::BLACK, _text.str());
  }
}

////////////////////////////////////////////////////////////////////////////////

SpinBox::SpinBox(int value, int min, int max)
{
  _value = value;
  _min = min;
  _max = max;
  
  setDim(120, 30);
  
  _up_button_down = false;
  _down_button_down = false;
  
  _value_rect.set(0, 0, 60, 30);
  _down_rect.set(60, 0, 30, 30);
  _up_rect.set(90, 0, 30, 30);
}

void SpinBox::setMin(int min)
{
  _min = min;
  
  if (_value < _min)
  {
    _value = _min;
    
    postEvent(SPIN_BOX_VALUE);
  }
}

void SpinBox::setMax(int max)
{
  _max = max;
  
  if (_value > _max)
  {
    _value = _max;
    
    postEvent(SPIN_BOX_VALUE);
  }
}

bool SpinBox::handleMousePress(const MousePressEvent& event)
{
  if (_up_rect.intersect(event.pos))
  {
    _up_button_down = true;
    
    _value += 1;
    
    if (_value > _max)
    {
      _value = _max;
    }
    
    postEvent(SPIN_BOX_VALUE);
  }
  else if (_down_rect.intersect(event.pos))
  {
    _down_button_down = true;
    
    _value -= 1;
    
    if (_value < _min)
    {
      _value = _min;
    }
    
    postEvent(SPIN_BOX_VALUE);
  }
  
  return true;
}

bool SpinBox::handleMouseRelease(const MousePressEvent& event)
{
  _up_button_down = false;
  _down_button_down = false;
  
  return true;
}

void SpinBox::draw()
{
  Rect rect(0, 0, _dim.w, _dim.h);
  char val_str[64];
  
  sprintf(val_str, "%d", _value);
  
  Draw_pushOffset(_pos);
  
  Draw_drawRect3D(_value_rect, 2, Colour::D_GREY, Colour::WHITE, Colour::L_GREY);
  GUI_print(_value_rect, TEXT_HORZ_ALIGN_CENTER, TEXT_VERT_ALIGN_CENTER,
    Colour::BLACK, val_str);
  
  if (_down_button_down)
  {
    Draw_drawRect3D(_down_rect, 2, Colour::D_GREY, Colour::GREY, Colour::L_GREY);
  }
  else
  {
    Draw_drawRect3D(_down_rect, 2, Colour::L_GREY, Colour::GREY, Colour::D_GREY);
  }
  
  Rect minus_rect(0, 0, 14, 4);
  minus_rect.centerIn(_down_rect);
  
  Draw_fillRect(minus_rect, Colour::BLACK);
  
  if (_up_button_down)
  {
    Draw_drawRect3D(_up_rect, 2, Colour::D_GREY, Colour::GREY, Colour::L_GREY);
  }
  else
  {
    Draw_drawRect3D(_up_rect, 2, Colour::L_GREY, Colour::GREY, Colour::D_GREY);
  }
  
  Rect horz_rect(0, 0, 14, 4);
  Rect vert_rect(0, 0, 4, 14);
  
  horz_rect.centerIn(_up_rect);
  vert_rect.centerIn(_up_rect);
  
  Draw_fillRect(horz_rect, Colour::BLACK);
  Draw_fillRect(vert_rect, Colour::BLACK);
    
  Draw_popOffset();
}

void SpinBox::onSetDim()
{
  
}

////////////////////////////////////////////////////////////////////////////////

TextField::TextField()
{
  setDim(120, 30);
  
  _length = 0;
  memset(_text, 0, sizeof(_text));
}

void TextField::setEnabled(bool enabled)
{
  _enabled = enabled;
}

bool TextField::handleKeyDown(const GUIKeyDownEvent* event)
{
  _text[_length++] = event->getChar();
  
  return true;
}

void TextField::draw()
{
  Rect rect(0, 0, _dim.w, _dim.h);
  Rect text_rect;
  Colour bg_colour;
  
  if (!_enabled)
  {
    bg_colour = Colour::GREY;
  }
  else if (GUI_hasFocus(this))
  {
    bg_colour = Colour(232, 232, 255, 255);
  }
  else
  {
    bg_colour = Colour::WHITE;
  }
  
  Draw_pushOffset(_pos);
  
  Draw_drawRect3D(rect, 2, Colour::D_GREY, bg_colour, Colour::L_GREY);
  
  text_rect.x = rect.x + 3;
  text_rect.y = rect.y;
  text_rect.w = rect.w - 6;
  text_rect.h = rect.h;
  
  GUI_print(text_rect, TEXT_HORZ_ALIGN_LEFT, TEXT_VERT_ALIGN_CENTER,
    Colour::BLACK, _text);
  
  Draw_popOffset();
}

////////////////////////////////////////////////////////////////////////////////

Viewport::Viewport(ViewportRenderer* renderer):
  _renderer(renderer)
{
  _renderer->onChangeDim(getDim());
}

void Viewport::draw()
{
  if (_renderer)
  {
    _renderer->draw();
  }
}

void Viewport::onSetDim()
{
  if (_renderer)
  {
    _renderer->onChangeDim(getDim());
  }
}

////////////////////////////////////////////////////////////////////////////////

void Panel::add(Widget* widget, int x, int y)
{
  widget->setParent(this);
  widget->setPos(x, y);
  
  _children.insert(widget);
}
  
Widget* Panel::getWidget(const Point& pos)
{
  Point p;
  
  for (int i = 0; i < _children.length(); i++)
  {
    if (_children[i]->intersect(pos))
    {
      p = pos - _children[i]->getPos();
      
      return _children[i]->getWidget(p);
    }
  }
  
  return this;
}
  
void Panel::doLayout()
{
  
}

void Panel::draw()
{
  for (int i = 0; i < _children.length(); i++)
  {
    _children[i]->draw();
  }
}

////////////////////////////////////////////////////////////////////////////////

Column::Column()
{
  _spacing = 0;
}

void Column::setSpacing(int spacing)
{
  _spacing = spacing;
}

void Column::add(Widget* widget)
{
  widget->setParent(this);
  
  _children.insert(widget);
}

Widget* Column::getWidget(const Point& pos)
{
  Point p;
  
  for (int i = 0; i < _children.length(); i++)
  {
    if (_children[i]->intersect(pos))
    {
      p = pos - _children[i]->getPos();
      
      return _children[i]->getWidget(p);
    }
  }
  
  return this;
}

void Column::doLayout()
{
  Dimension dim(0, 0);
  int x;
  int y = 0;
  
  for (int i = 0; i < _children.length(); i++)
  {
    _children[i]->doLayout();
    
    dim.h += _children[i]->getDim().h;
    
    if (i != 0)
    {
      dim.h += _spacing;
    }
    
    dim.w = Math_max<int>(dim.w, _children[i]->getDim().w);
  }
  
  for (int i = 0; i < _children.length(); i++)
  {
    x = (dim.w - _children[i]->getDim().w) / 2;
    
    _children[i]->setPos(x, y);
    
    y += _children[i]->getDim().h + _spacing;
  }
  
  setDim(dim);
}

void Column::draw()
{
  for (int i = 0; i < _children.length(); i++)
  {
    _children[i]->draw();
  }
}

void Column::onSetDim()
{
  Dimension dim(0, 0);
  Point p;
  
  for (int i = 0; i < _children.length(); i++)
  {
    dim.h += _children[i]->getDim().h;
    
    if (i != 0)
    {
      dim.h += _spacing;
    }
    
    dim.w = Math_max<int>(dim.w, _children[i]->getDim().w);
  }
  
  p.y = (_dim.h - dim.h) / 2;
  
  for (int i = 0; i < _children.length(); i++)
  {
    p.x = (_dim.w - _children[i]->getDim().w) / 2;
    
    _children[i]->setPos(p.x, p.y);
    
    p.y += _children[i]->getDim().h + _spacing;
  }
}

////////////////////////////////////////////////////////////////////////////////

Background::Background()
{
  _colour = Colour::GREY;
}
  
void Background::setColour(Colour colour)
{
  _colour = colour;
}

void Background::draw()
{
  Graphics_setClearColour(_colour);
  Graphics_clearScreen(true, false, false);
}
